#include <iostream>
#include <unistd.h>
#include <assert.h>
#include<typeinfo>
#include <any>

namespace wyl
{
    class Any
    {
    private:
        // 抽象类
        class holder
        {
        public:
            virtual ~holder() {}
            virtual holder* clone() = 0;
            virtual const std::type_info &type() = 0;
        };

        template <class T>
        class placeholder : public holder
        {
        public:
            placeholder(const T &val) : _val(val) {}
            virtual holder* clone() { return new placeholder<T>(_val); }
            virtual const std::type_info &type() { return typeid(T); }

        public:
            T _val;
        };

    private:
        holder *_content;

    public:
        Any() :_content(nullptr){}
        ~Any(){ delete _content;} 

        template <class T>
        Any(const T& val) : _content(new placeholder<T>(val)) {}

        Any(const Any &other):_content(other._content ? other._content->clone() : nullptr) {}

        template <class T>
        Any& operator=(const T &val) {
            Any(val).swap(*this);
            return *this;
        }
        Any& operator=(const Any &other) {
            Any(other).swap(*this);
            return *this;
        }

    public:
        void swap(Any &other) {
            std::swap(_content,other._content);
        }
        template <class T>
        T *get()
        {
            assert(typeid(T) == _content->type());
            return &((placeholder<T>*)_content)->_val;
        }
    };


    class Task
    {
    public:
        Task(){std::cout << "Task()" << std::endl;}
        ~Task(){std::cout << "~Task()" << std::endl;}
    };

    void test()
    {
        std::any a;
        a = 5;
        int* pa = std::any_cast<int>(&a);
        std::cout << *pa << std::endl;
        a = std::string("hello");

        std::string* ps = std::any_cast<std::string>(&a);
        std::cout << *ps << std::endl;

        Any b;
        {
            Task t;
            b = t;
        }
    }
};

int main()
{
    wyl::test();
    return 0 ;
}
